package dataImport.action;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import dataImport.action.abstracts.AbstractEntityReader;
import dataImport.action.helper.UnityGuardian;
import dataImport.action.manager.EntityReaderManager;
import dataImport.exception.DuplicateAttributeException;
import dataImport.exception.DuplicateDeclarationException;
import dataImport.exception.MissingAttributeException;
import dataImport.exception.MissingDeclarationException;
import dataImport.exception.NoEntityRelatedWithException;
import dataImport.exception.UniquenessRestrictionViolatedException;
import dataImport.model.Configuration;
import dataImport.model.CustomAction;
import dataImport.model.Object;
import dataImport.model.Place;
import dataImport.model.State;
import dataImport.model.StaticConfiguration;
import dataImport.model.abstracts.AbstractEntity;


public class ConfigurationReader extends AbstractEntityReader {

	private static final long serialVersionUID = 1882448166070850033L;

	private static final String ENTITY_NAME = "configuration";

	private static final String ATTRIBUTE_VALUE = "value";

	private UnityGuardian staticConfigurationEntityId;

	public ConfigurationReader(final EntityReaderManager entityReaderManager) {
		super(entityReaderManager);
		this.staticConfigurationEntityId = new UnityGuardian();
	}

	@Override
	protected AbstractEntity createEntity(final Element element) {
		final String name = element.getNodeName();
		final String value = element.getAttribute(ATTRIBUTE_VALUE);
		final Element parentNode = (Element) element.getParentNode();
		final String parentNodeName = parentNode.getNodeName();

		this.verifyRestrictions(parentNodeName, name, value);

		final StaticConfiguration staticConfiguration = StaticConfiguration.get(name);

		switch (staticConfiguration) {
			case INITIALACTION:
				final CustomAction customAction = (CustomAction) super.getEntityReaderManager().getCustomActionReader().getEntityWithId(value);
				return new Configuration(staticConfiguration, customAction);
			case INITIALOBJECT:
				final Object object = (Object) super.getEntityReaderManager().getObjectReader().getEntityWithId(value);
				return new Configuration(staticConfiguration, object);
			case INITIALSTATE:
				final State state = (State) super.getEntityReaderManager().getStateReader().getEntityWithId(value);
				return new Configuration(staticConfiguration, state);
			case INITIALPLACE:
				final Place place = (Place) super.getEntityReaderManager().getPlaceReader().getEntityWithId(value);
				return new Configuration(staticConfiguration, place);
			default:
				break;
		}

		return null;
	}

	@Override
	public void read(final Document document) {
		final NodeList nodeList = document.getElementsByTagName(ConfigurationReader.ENTITY_NAME);

		if (nodeList.getLength() == 0) {
			throw new MissingDeclarationException(ConfigurationReader.ENTITY_NAME);
		}

		if (nodeList.getLength() > 1) {
			throw new DuplicateDeclarationException(ConfigurationReader.ENTITY_NAME);
		}

		for (StaticConfiguration staticConfiguration : StaticConfiguration.values()) {
			super.read(staticConfiguration.getName(), document);
		}
	}

	private void verifyRestrictions(final String configurationName, final String staticConfigurationName, final String entityId) {
		if (entityId.isEmpty()) {
			throw new MissingAttributeException(ATTRIBUTE_VALUE);
		}

		try {
			this.staticConfigurationEntityId.ensureUniqueness(staticConfigurationName, entityId);
		}
		catch (final UniquenessRestrictionViolatedException e) {
			throw new DuplicateAttributeException("configuration", staticConfigurationName);
		}

		if (!configurationName.equals(ConfigurationReader.ENTITY_NAME)) {
			throw new NoEntityRelatedWithException(staticConfigurationName, ConfigurationReader.ENTITY_NAME);
		}
	}
}
